package terrforming.space.objects;

/**
 * Любой подвижный объект - подвид космического объекта
 */
public abstract class  MovableCosmicObject extends CosmicObject{
    
    /** компоненты скорости */
    protected float vx=0,vy=0;
    
    /** компоненты ускорения */
    protected float ax=0,ay=0;
    
    /** номер индекса для записи*/
    private int ri=0;
    /** список позиций для расчета центростремительного ускорения */
    private float[] rx = {Float.NaN,Float.NaN,Float.NaN};
    private float[] ry = {Float.NaN,Float.NaN,Float.NaN};
    private float a,b,c,d,rx0,ry0,dr,acpr,atx,aty;
        
    /** пересчет позиций, скоростей и ускорений */
    public void recalculate(){
        ax=0;
        ay=0;
        //расчет центростремительного ускорения
        if (rx[0]!=Float.NaN&&rx[1]!=Float.NaN&&rx[2]!=Float.NaN&&ry[0]!=Float.NaN&&ry[1]!=Float.NaN&&ry[2]!=Float.NaN){
            //проверено!
            a = rx[0]*(ry[1]-ry[2])+rx[1]*(ry[2]-ry[0])+rx[2]*(ry[0]-ry[1]); 
            //внесено исправление!
            b = rx[0]*rx[0]*(ry[2]-ry[1]) + rx[1]*rx[1]*(ry[0]-ry[2]) + rx[2]*rx[2]*(ry[1]-ry[0]) + ry[0]*ry[0]*(ry[2]-ry[1]) + ry[1]*ry[1]*(ry[0]-ry[2]) + ry[2]*ry[2]*(ry[1]-ry[0]);
            //проверено!
            c = rx[0]*rx[0]*(rx[1]-rx[2]) + rx[1]*rx[1]*(rx[2]-rx[0]) + rx[2]*rx[2]*(rx[0]-rx[1]) + ry[0]*ry[0]*(rx[1]-rx[2]) + ry[1]*ry[1]*(rx[2]-rx[0]) + ry[2]*ry[2]*(rx[0]-rx[1]);
            //проверено!
            d = rx[0]*rx[0]*(rx[1]*ry[2]+rx[2]*ry[1]) + rx[1]*rx[1]*(rx[0]*ry[2]-rx[2]*ry[0]) + rx[2]*rx[2]*(rx[1]*ry[0]-rx[0]*ry[1]) + ry[0]*ry[0]*(rx[2]*ry[1]-rx[1]*ry[2]) + ry[1]*ry[1]*(rx[0]*ry[2]-rx[2]*ry[0]) + ry[2]*ry[2]*(rx[1]*ry[0]-rx[0]*ry[1]);
            //r = (float)Math.sqrt(-d/a+(b*b+c*c)/(4*a*a)); //- хз какая правильная, но есть различия. вторая чаще дает результат!!!
            r=(float)Math.sqrt((b*b+c*c)/(a*a)-4*d/a)/2;
            rx0=-b/(2*a); //x центра окружности
            ry0=-c/(2*a); //y центра окружности
            float vsqrd=vx*vx+vy*vy; //скорость
            acpr=vsqrd/(dr*dr); //центростремительное ускорение. осталось лишь домножить на разность координат по оси
            atx=acpr*(x-rx0);
            aty=acpr*(y-ry0);
//            System.err.println("x: "+x + " y: "+y);
//            System.err.println("a: "+a + " b: "+b+ " c: " + c + " d: " + d);
//            System.err.println("r:" + r + " rx0: "+ rx0 + " ry0: "+ry0);
//            System.err.println("atx: "+atx+" aty: "+aty);
        }
        //расчет ускорения от гравитации
        for (CosmicObject  cobj: Universe.getInstance().getObjects()) {
            //объект не взаимодействует сам с собой!
            if (this==cobj) continue;
            //расстояние до объекта
            double distsqrd = (cobj.x-x)*(cobj.x-x)+(cobj.y-y)*(cobj.y-y);
            double dist = Math.sqrt(distsqrd);
            //!!!ВНИМАНИЕ!!!
            //если дистанция становится нулевой, то ускорение становится бесконечным
            //нужно какое-то решения для данной ситуации
            if (dist==0) continue;
            //ускорение
            double a = cobj.getM()*Universe.G/(distsqrd*Universe.M*Universe.M);
            //проекция ускорения на оси
            //первая составляющая - ускорение свободного падения, вторая - центростремительное ускорение
            ax+=a*(cobj.x-x)/dist;
            ay+=a*(cobj.y-y)/dist;
            if (dist<=cobj.r) {
                //метод класса CosmicObject
                remove();
            }
        }
        //
        
        float absac = (float)Math.sqrt(atx*atx+aty*aty);
        //if (atx!=atx||aty!=aty) System.err.println(atx+" : "+aty);
        if (!(absac!=absac)){
            //System.out.println(absac+" : "+Math.sqrt(ax*ax+ay*ay));
            //ax+=atx;
            //ay+=aty;
        }
        //обработка сингулярности
//        Singularity sglrt = Universe.getInstance().getSglrt();
//        if (sglrt.isActive()) {
//            //расстояние до объекта
//            double distsqrd = (sglrt.x-x)*(sglrt.x-x)+(sglrt.y-y)*(sglrt.y-y);
//            double dist = Math.sqrt(distsqrd);
//            //!!!ВНИМАНИЕ!!!
//            //если дистанция становится нулевой, то ускорение становится бесконечным
//            //нужно какое-то решения для данной ситуации
//            if (dist!=0) {
//                //ускорение
//                double a = sglrt.getM()*Universe.G/distsqrd;
//                double vsqrd=vx*vx+vy*vy;
//                //проекция ускорения на оси
//                ax+=(a-vsqrd/dist)*(x-sglrt.x)/dist;
//                ay+=(a-vsqrd/dist)*(y-sglrt.y)/dist;
//            }
//        }
        if (ax!=ax) {
            ax=0;
        }
        if (ay!=ay) {
            ay=0;
        }
        x+=vx;
        y+=vy;
        vx+=ax;
        vy+=ay;
        
//        if (vx>=0.0006f) vx=0.0006f;
//        if (vx<=-0.0006f) vx=-0.0006f;
//        if (vy>=0.0006f) vy=0.0006f;
//        if (vy<=-0.0006f) vy=-0.0006f;
        
        rx[0]=rx[1];
        ry[0]=ry[1];
        rx[1]=rx[2];
        ry[1]=ry[2];
        rx[2]=x;
        ry[2]=y;
        ri++;
    }

    /** получить скорость по x */
    public float getVx() {
        return vx;
    }

    /** установить скорость по x */
    public void setVx(float vx) {
        this.vx = vx;
    }

    /** получить скорость по y */
    public float getVy() {
        return vy;
    }

    /** установить скорость по y */
    public void setVy(float vy) {
        this.vy = vy;
    }

    /** получить ускорение по x */
    public float getAx() {
        return ax;
    }

    /** установить ускорение по x */
    public void setAx(float ax) {
        this.ax = ax;
    }

    /** получить ускорение по y */
    public float getAy() {
        return ay;
    }

    /** установить ускорение по y */
    public void setAy(float ay) {
        this.ay = ay;
    }
    
    
    
}
